package Search;

import java.util.ArrayList;

import Main.Board;
import Main.Node;

public class GSearch extends Problem {

	public static int getSolutionCost() {
		return solutionCost;
	}

	public static void setSolutionCost(int solutionCost) {
		GSearch.solutionCost = solutionCost;
	}

	public static int getNodesExpanded() {
		return nodesExpanded;
	}

	public static void setNodesExpanded(int nodesExpanded) {
		GSearch.nodesExpanded = nodesExpanded;
	}

	static int nodesExpanded = 0;

	public static String compress(int[][] b) {
		String str = "";
		for (int i = 0; i < b.length; i++) {
			for (int j = 0; j < b.length; j++) {
				str += b[i][j];
			}
		}
		return str;
	}

	public static boolean checkDone(int[][] a) {
		String str = compress(a);
		for (int i = 0; i < Mem.size(); i++) {
			if (str.compareTo(Mem.get(i)) == 0)
				return false;
		}
		Mem.add(str);
		return true;
	}

	public static ArrayList<Node> expand(Node currentNode) {

		nodesExpanded++;
		ArrayList<Node> result = new ArrayList<Node>();
		boolean[] canMove = currentNode.getBoard().possibleMoves();

		// remove reversed operation for the same tile from possibility
		int id = currentNode.getTileID();
		if (id == 1) {// M
			canMove[0] = canMove[1] = false;
		} else {
			if (id < 300) {// V2
				for (int i = 2 + currentNode.getBoard().getH2n() * 2; i < (2 * (1 + currentNode
						.getBoard().getH2n() + currentNode.getBoard().getV2n())); i++) {
					if (i / 2 - 2 * currentNode.getBoard().getH2n() == id) {
						canMove[i] = canMove[i + 1] = false;
						break;
					}
				}
			} else {
				if (id < 400) { // V3
					for (int i = 2 * (1 + currentNode.getBoard().getH2n() + currentNode
							.getBoard().getV2n()); i < canMove.length; i++) {
						if (i / 2 - 2 * currentNode.getBoard().getH2n() - 2
								* currentNode.getBoard().getV2n() == id) {
							canMove[i] = canMove[i + 1] = false;
							break;
						}
					}
				} else {
					if (id > 1999) { // H
						for (int i = 2; i < (2 * (currentNode.getBoard()
								.getH2n() + 1)); i++) {
							if (i / 2 == id) {
								canMove[i] = canMove[i + 1] = false;
								break;
							}
						}
					}
				}
			}
		}
		for (int i = 0; i < canMove.length; i++) {

		}
		int nextLevel = currentNode.getLevel() + 1;
		// Board newBoard;
		// Mouse
		if (canMove[0]) {
			Board newBoard = currentNode.getBoard().clone();
			newBoard.move(1, 'l');
			Node temp = new Node('l', 1, newBoard, nextLevel, currentNode);
			temp.setCostSoFar(currentNode.getCostSoFar() + 1);
			result.add(temp);

		}
		if (canMove[1]) {
			Board newBoard = currentNode.getBoard().clone();
			newBoard.move(1, 'r');
			Node temp = new Node('r', 1, newBoard, nextLevel, currentNode);
			temp.setCostSoFar(currentNode.getCostSoFar() + 1);
			result.add(temp);
		}
		for (int i = 2; i < canMove.length; i++) {
			if (canMove[i]) {
				Board newBoard = currentNode.getBoard().clone();
				if (i < 2 * (newBoard.getH2n() + 1)) { // H2
					char dir = (i % 2 == 1) ? 'r' : 'l';
					newBoard.move(2000 + i / 2, dir);
					Node temp = new Node((i % 2 == 1) ? 'r' : 'l',
							2000 + i / 2, newBoard, nextLevel, currentNode);
					temp.setCostSoFar(currentNode.getCostSoFar() + 1);
					result.add(temp);
				} else {
					if (i < 2 * (newBoard.getV2n() + newBoard.getH2n() + 1)) { // V2
						char dir = (i % 2 == 1) ? 'd' : 'u';
						newBoard.move(200 + i / 2 - newBoard.getH2n(), dir);
						Node temp = new Node((i % 2 == 1) ? 'd' : 'u', 200 + i
								/ 2 - newBoard.getH2n(), newBoard, nextLevel,
								currentNode);
						temp.setCostSoFar(currentNode.getCostSoFar() + 1);
						result.add(temp);
					} else { // V3
						char dir = (i % 2 == 1) ? 'd' : 'u';
						newBoard.move(300 + i / 2 - newBoard.getH2n()
								- newBoard.getV2n(), dir);
						Node temp = new Node((i % 2 == 1) ? 'd' : 'u', 300 + i
								/ 2 - newBoard.getH2n() - newBoard.getV2n(),
								newBoard, nextLevel, currentNode);
						temp.setCostSoFar(currentNode.getCostSoFar() + 1);
						result.add(temp);
					}
				}
			}
		}
		return result;
	}

	public static ArrayList<Node> formPath(Node Goal) {
		ArrayList<Node> Path = new ArrayList<Node>();
		Node n = Goal;
		while (n != null) {
			Path.add(0, n);
			n = n.getParent();
		}
		return Path;
	}

	public static void displayPath(ArrayList<Node> path) {
		int l = path.size();
		while (!path.isEmpty()) {
			if (trace || path.size() == l)
				path.remove(0).getBoard().display();
			else
				path.remove(0);
			String str = "==> ";
			if (path.isEmpty()) {
				str += "M move r";
				System.out.println(str);
				return;
			}
			switch (path.get(0).getTileID() / 100) {
			case 0:
				str += "M";
				break;
			case 2:
				str += "v" + path.get(0).getTileID() % 100;
				break;
			case 3:
				str += "V" + path.get(0).getTileID() % 100;
				break;
			case 20:
				str += "H" + path.get(0).getTileID() % 100;
				break;
			}
			str += " move " + path.get(0).getOperator();
			System.out.println(str);
		}
	}
}